home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nothing but Tetris
/
Nothing but Tetris.iso
/
amiga
/
workbench_tris
/
tetris.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-19
|
15KB
|
458 lines
/*
Copyright (c) 1992, Trevor Smigiel. All rights reserved.
(I hope Commodore doesn't mind that I borrowed their copyright notice.)
The source and executable code of this program may only be distributed in free
electronic form, via bulletin board or as part of a fully non-commercial and
freely redistributable diskette. Both the source and executable code (including
comments) must be included, without modification, in any copy. This example may
not be published in printed form or distributed with any commercial product.
This program is provided "as-is" and is subject to change; no warranties are
made. All use is at your own risk. No liability or responsibility is assumed.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <math.h>
#include <stdio.h>
#include "tetris.h"
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include "main_protos.h"
#include "TetrisImages_protos.h"
struct TBoard *
NewBoard(struct RastPort *rp, WORD bleft, WORD btop)
{
struct TBoard *board;
int i;
board = AllocMem(sizeof(struct TBoard), MEMF_CLEAR);
if (board) {
InitBitMap(&board->bitmap, Depth, PWidth, PHeight);
board->bitmap.Planes[0] = AllocMem(board->bitmap.BytesPerRow * board->bitmap.Rows * board->bitmap.Depth, MEMF_CHIP | MEMF_CLEAR);
if (board->bitmap.Planes[0]) {
for (i = 1; i < Depth; i++)
board->bitmap.Planes[i] = board->bitmap.Planes[i-1] + board->bitmap.BytesPerRow;
board->bitmap.BytesPerRow *= Depth;
board->rastport = rp;
board->board_off.x = bleft;
board->board_off.y = btop;
board->score_off.x = bleft;
board->score_off.y = 1 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
board->line_off.x = bleft;
board->line_off.y = 3 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
board->time_off.x = bleft;
board->time_off.y = 2 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
board->next_off.x = bleft + PWidth - XSize * 4;
board->next_off.y = btop - ((YSize * 7) / 2);
for (i = 0; i < PFHEIGHT; i++) {
board->level.board[i] = 0x801f;
}
board->level.board[i] = 0xffff;
board->level.goal = GOAL_TIME_LIMIT | GOAL_CLEAR_LINES;
board->level.lines = 5;
board->level.time = 60;
board->level.line_up = 30;
CurrentTime((LONG *)&board->seed[1], (LONG *)&board->seed[0]);
board->next_which = TFirst[nrand48(board->seed) % 7];
board->piece.which = TFirst[nrand48(board->seed) % 7];
board->piece.bx = (PFWIDTH / 2) - 2;
board->piece.x = board->piece.bx * XSize;
board->piece.by = 0;
board->piece.y = 0;
board->next_sec = UPDATE_SECONDS;
board->points = 0;
board->clevel = Level;
board->next_line_up = board->level.line_up;
board->drop_up = 30;
board->next_drop_up = board->drop_up;
board->drop = 10;
board->next_drop = board->drop;
board->lines = board->level.lines;
board->time = board->level.time;
return board;
}
FreeMem(board, sizeof(struct TBoard));
}
return NULL;
}
void
FreeBoard(struct TBoard *board)
{
FreeMem(board->bitmap.Planes[0], board->bitmap.BytesPerRow * board->bitmap.Rows);
FreeMem(board, sizeof(struct TBoard));
}
void
AddPiece(struct TBoard *board)
{
UWORD piece = TPieces[board->piece.which], p;
UWORD *b = &board->level.board[board->piece.by];
WORD x = board->piece.bx + 1;
*b |= ((piece & 0xf000) >> x);
if (p = piece & 0x0f00) {
b++; x -= 4;
*b |= ((x >= 0) ? (p >> x) : (p << -x));
if (p = piece & 0x00f0) {
b++; x -= 4;
*b |= ((x >= 0) ? (p >> x) : (p << -x));
if (p = piece & 0x000f) {
b++; x -= 4;
*b |= ((x >= 0) ? (p >> x) : (p << -x));
}
}
}
}
WORD
TestMove(struct TBoard *board, WORD which, WORD x, WORD y)
{
UWORD piece = TPieces[which];
UWORD *b = &board->level.board[y];
UWORD p;
x++;
if (*b & ((piece & 0xf000) >> x)) return 0;
if (p = piece & 0x0f00) {
b++; x -= 4;
if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
if (p = piece & 0x00f0) {
b++; x -= 4;
if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
if (p = piece & 0x000f) {
b++; x -= 4;
if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
}
}
}
return 1;
}
void
CheckRows(struct TBoard *board, WORD btop, WORD pheight)
{
UWORD *b, *src, *dst;
WORD top, height, ymax;
int first;
int i, j;
char buf[12];
int pt = 0;
top = 0;
for (i = btop - 1; board->level.board[i] & 0x7fe0; i--);
first = i + 1;
top = first * YSize;
height = (btop - first) * YSize;
ymax = board->board_off.y + top + height + YSize - 1;
for (b = &board->level.board[btop], i = 0; i < pheight; i++, b++) {
if (*b == 0xffff) {
if (height)
BltBitMap(&board->bitmap, 0, top, &board->bitmap, 0, top + YSize, PWidth, height, 0xC0, 0xff, NULL);
BltClear(board->bitmap.Planes[0] + top * board->bitmap.BytesPerRow, board->bitmap.BytesPerRow * YSize, 0);
ScrollRaster(board->rastport, 0, -YSize, board->board_off.x, board->board_off.y + top, board->board_off.x + PWidth - 1, ymax);
for (src = b - 1, dst = b, j = i + btop - first; j > 0; j--)
*dst-- = *src--;
board->level.board[first] = 0x801f;
top += YSize;
first++;
pt++;
board->points += pt;
sprintf(buf, "Score:%4d", board->points);
Move(board->rastport, board->score_off.x, board->score_off.y);
Text(board->rastport, buf, 10);
board->lines--;
sprintf(buf, "Lines:%4d", board->lines);
Move(board->rastport, board->line_off.x, board->line_off.y);
Text(board->rastport, buf, 10);
if ((board->level.goal & GOAL_CLEAR_LINES) && (board->lines <= 0)) {
board->flags |= TETF_NEXTLEVEL;
}
} else {
height += YSize;
}
ymax += YSize;
}
}
void
PrintBits(struct TBoard *board)
{
int i, j;
for (i = 0; i <= PFHEIGHT; i++) {
for (j = 0x4000; j & 0x7fe0; j >>= 1)
printf((j & board->level.board[i]) ? "1" : "0");
printf("\n");
}
printf("\n");
}
void
MoveTetris(struct TBoard *board, WORD move)
{
struct TPiece npiece;
WORD left, top, width, height;
if ((board) && (board->flags & (TETF_GAMEOVER | TETF_NEXTLEVEL))) return;
npiece = board->piece;
left = board->piece.x;
top = board->piece.y;
width = TSizes[board->piece.which].x;
height = TSizes[board->piece.which].y;
switch (move) {
case COMMAND_DOWN:
npiece.by++;
npiece.y += YSize;
height += YSize;
break;
case COMMAND_LEFT:
npiece.bx--;
npiece.x -= XSize;
left -= XSize;
width += XSize;
break;
case COMMAND_RIGHT:
npiece.bx++;
npiece.x += XSize;
width += XSize;
break;
case COMMAND_ROTATE:
npiece.which = TNext[npiece.which];
if (TSizes[npiece.which].x > width) width = TSizes[npiece.which].x;
if (TSizes[npiece.which].y > height) height = TSizes[npiece.which].y;
break;
default: break;
}
if (TestMove(board, npiece.which, npiece.bx, npiece.by)) {
BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22, 0xff, NULL);
board->piece = npiece;
BltBitMap(&TBitMaps[npiece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[npiece.which].x, TSizes[npiece.which].y, 0xEE, 0xff, NULL);
WaitTOF();
BltBitMapRastPort(&board->bitmap, left, top, board->rastport, board->board_off.x + left, board->board_off.y + top, width, height, 0xC0);
} else if (move == COMMAND_DOWN) {
AddPiece(board);
CheckRows(board, board->piece.by, TSSizes[board->piece.which].y);
board->piece.bx = (PFWIDTH / 2) - 2;
board->piece.x = board->piece.bx * XSize;
board->piece.by = 0;
board->piece.y = 0;
board->piece.which = board->next_which;
board->next_which = TFirst[nrand48(board->seed) % 7];
//board->pieces[board->piece.which]++;
BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
BltBitMapRastPort(&board->bitmap, board->piece.x, board->piece.y, board->rastport, board->board_off.x + board->piece.x, board->board_off.y + board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xC0);
BltBitMapRastPort(&TBitMaps[board->piece.which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22);
BltBitMapRastPort(&TBitMaps[board->next_which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->next_which].x, TSizes[board->next_which].y, 0xC0);
if (!TestMove(board, board->piece.which, board->piece.bx, board->piece.by))
board->flags |= TETF_GAMEOVER | TETF_OUTOFROOM;
}
}
void
DrawLine(struct TBoard *board, WORD line)
{
int i, top, left, size = YSize * board->bitmap.BytesPerRow;
BltClear(board->bitmap.Planes[0] + line * size, size, 0);
top = line * YSize;
for (left = 0, i = 0x4000; i & 0x7fe0; i >>= 1, left += XSize) {
if (board->level.board[line] & i)
BltBitMap((struct BitMap *)&TBitMaps[19], 0, 0, &board->bitmap, left, top, XSize, YSize, 0xC0, 0xff, NULL);
}
}
/* called every timer event, (every 1/10th of a second) */
void
UpdateTetris(struct TBoard *board)
{
int i;
char buf[12];
if ((board) && (board->flags & (TETF_GAMEOVER | TETF_NEXTLEVEL))) return;
board->next_drop--;
if (board->next_drop < 0) {
board->next_drop = board->drop;
MoveTetris(board, COMMAND_DOWN);
}
board->next_sec--;
if (board->next_sec < 0) {
board->next_sec = UPDATE_SECONDS;
board->time--;
sprintf(buf, "Time:%2d:%02d", board->time / 60, board->time % 60);
Move(board->rastport, board->time_off.x, board->time_off.y);
Text(board->rastport, buf, 10);
if (board->time <= 0) {
if (board->level.goal & GOAL_TIME_LIMIT)
board->flags |= TETF_GAMEOVER | TETF_OUTOFTIME;
else if (board->level.goal & GOAL_ENDURANCE)
board->flags |= TETF_NEXTLEVEL;
}
board->next_line_up--;
if (board->next_line_up < 0) {
board->next_line_up = board->level.line_up;
for (i = 0; i < PFHEIGHT; i++)
board->level.board[i] = board->level.board[i + 1];
board->level.board[PFHEIGHT - 1] &= ~(0x20 << (lrand48() % 10));
/* move piece up */
if (board->piece.by) {
board->piece.by--;
board->piece.y -= YSize;
} else {
/* Erase piece */
BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22, 0xff, NULL);
/* Redraw piece down one so that its in the right place when the board is scrolled up */
BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y + YSize, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
}
/* scroll board up */
BltBitMap(&board->bitmap, 0, YSize, &board->bitmap, 0, 0, PWidth, PHeight - YSize, 0xC0, 0xff, NULL);
/* draw the new line */
DrawLine(board, PFHEIGHT - 1);
/* update entire board to screen */
BltBitMapRastPort(&board->bitmap, 0, 0, board->rastport, board->board_off.x, board->board_off.y, PWidth, PHeight, 0xC0);
}
board->next_drop_up--;
if (board->next_drop_up < 0) {
board->next_drop_up = board->drop_up;
if (board->drop) board->drop--;
}
}
}
void
DrawBoard(struct TBoard *board)
{
int len;
char buf[12];
SetAPen(board->rastport, 3);
RectFill(board->rastport, board->board_off.x - BSize, board->board_off.y, board->board_off.x, board->board_off.y + PHeight + BSize - 1);
RectFill(board->rastport, board->board_off.x - 1, board->board_off.y + PHeight, board->board_off.x + PWidth, board->board_off.y + PHeight + BSize - 1);
RectFill(board->rastport, board->board_off.x + PWidth, board->board_off.y, board->board_off.x + PWidth + BSize - 1, board->board_off.y + PHeight + BSize - 1);
SetAPen(board->rastport, 2);
Move(board->rastport, board->board_off.x - 1, board->board_off.y);
Draw(board->rastport, board->board_off.x - BSize, board->board_off.y);
Draw(board->rastport, board->board_off.x - BSize, board->board_off.y + PHeight + BSize - 1);
SetAPen(board->rastport, 1);
Move(board->rastport, board->board_off.x - BSize + 1, board->board_off.y + PHeight + BSize - 1);
Draw(board->rastport, board->board_off.x + PWidth + BSize - 1, board->board_off.y + PHeight + BSize - 1);
Draw(board->rastport, board->board_off.x + PWidth + BSize - 1, board->board_off.y);
SetAPen(board->rastport, 2);
Draw(board->rastport, board->board_off.x + PWidth, board->board_off.y);
Draw(board->rastport, board->board_off.x + PWidth, board->board_off.y + PHeight);
Draw(board->rastport, board->board_off.x - 1, board->board_off.y + PHeight);
SetAPen(board->rastport, 1);
Draw(board->rastport, board->board_off.x - 1, board->board_off.y + 1);
BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
BltBitMapRastPort(&board->bitmap, 0, 0, board->rastport, board->board_off.x, board->board_off.y, PWidth, PHeight, 0xC0);
EraseRect(board->rastport, board->next_off.x, board->next_off.y, board->next_off.x + XSize * 4 - 1, board->next_off.y + YSize * 7 / 2 - 1);
BltBitMapRastPort(&TBitMaps[board->next_which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->next_which].x, TSizes[board->next_which].y, 0xC0);
len = sprintf(buf, "Score:%4d", board->points);
Move(board->rastport, board->score_off.x, board->score_off.y);
Text(board->rastport, buf, len);
len = sprintf(buf, "Lines:%4d", board->lines);
Move(board->rastport, board->line_off.x, board->line_off.y);
Text(board->rastport, buf, len);
len = sprintf(buf, "Time:%2d:%02d", board->time / 60, board->time % 60);
Move(board->rastport, board->time_off.x, board->time_off.y);
Text(board->rastport, buf, len);
}
void
StartLevel(struct TBoard *board, WORD l)
{
int i;
char filename[32];
BPTR file;
if ((board) && (board->flags & TETF_GAMEOVER)) return;
BltClear(board->bitmap.Planes[0], board->bitmap.Rows * board->bitmap.BytesPerRow, 0);
sprintf(filename, "tetris:levels/%d", l);
file = Open(filename, MODE_OLDFILE);
if (file) {
Read(file, &board->level, sizeof(struct TLevel));
Close(file);
for (i = 0; i < PFHEIGHT; i++) {
DrawLine(board, i);
}
} else {
board->level.goal = GOAL_TIME_LIMIT | GOAL_CLEAR_LINES;
board->level.lines = 5 + l * 5;
board->level.time = 60 + l * 30;
board->level.line_up = 45 - l * 5 / 2;
for (i = 0; i < PFHEIGHT; i++) {
board->level.board[i] = 0x801f;
}
board->level.board[i] = 0xffff;
}
board->flags &= ~TETF_NEXTLEVEL;
board->lines = 0;
board->next_which = TFirst[nrand48(board->seed) % 7];
board->piece.which = TFirst[nrand48(board->seed) % 7];
board->piece.bx = (PFWIDTH / 2) - 2;
board->piece.x = board->piece.bx * XSize;
board->piece.by = 0;
board->piece.y = 0;
// board->drop_up -= 1;
// board->drop = board->drop_up;
board->next_drop = board->drop;
board->next_sec = UPDATE_SECONDS;
board->lines = board->level.lines;
board->time = board->level.time;
board->next_line_up = board->level.line_up;
board->next_drop_up = board->drop_up;
board->clevel = l;
DrawBoard(board);
}
/*
void
EndLevel(struct TBoard *board)
{
}
*/